import { AudioClip, AudioSource, Node } from "cc";
import { App } from "../App";
import { Singleton, EventConst, LocalKey, AudioVol } from "./Common";

export default class audioManager extends Singleton<audioManager> {
    private _audioVol:AudioVol = null;
    private _isHide:boolean = false;
    private _clips:Map<string,AudioClip> = null;
    private _audioSource:AudioSource = null;

    protected onInit(bindNode:Node){
        if (!App.isValid(bindNode)){
            throw new Error(`AudioManager is must bind one Node.`);
        }

        this._audioSource = (bindNode.getComponent(AudioSource) || bindNode.addComponent(AudioSource)); 
        this._audioVol = App.getLocalStorage(LocalKey.AUDIO,{music:0,effect:1.0});
        this._audioSource.volume = this._audioVol.music;
        this._clips = new Map<string,AudioClip>();

        App.Event.on(EventConst.APP_HIDE,()=>{
            this._isHide = true;
            this._audioSource.pause();
        },this);
        App.Event.on(EventConst.APP_SHOW,()=>{
            this._isHide = false;
            this._audioVol.music > 0.0 && this._audioSource.play();
        },this);
    }

    protected onDestroy(){
        this._audioSource.destroy();
        delete this._audioSource;
    }

    public keepPlay(): void {
        if (this._audioSource){
            this._audioSource.playOnAwake = true;
            this._audioVol.music > 0 && !this._audioSource.playing && this._audioSource.play();
        }
    }

    /**
     * 播放
     * @param filePath 文件名
     * @param isEffect 是否音效
     */
    public play(file: string | AudioClip, effect: boolean = true,loop:boolean=false): void {
        if (typeof(file) === 'string'){
            const clip:AudioClip = this._clips.get(file);
            if (!App.isValid(clip)){
                App.Asset.load(file,(clip: AudioClip)=>{
                    this._clips.set(file,clip);
                    !this._isHide && this._playClip(clip,!effect,loop);
                },AudioClip);
                return ;
            }
            !this._isHide && this._playClip(clip,!effect,loop);
            return ;
        }
        !this._isHide && this._playClip(file as AudioClip,!effect,loop);
    };

    /**
     * 随机播放指定数组音乐
     * @param arr 播放文件数组
     */
    public playGroup(paths:string[],random:boolean = true): void {
        if (!paths || paths.length < 1) return ;

        let _playing:boolean = false;
        const clips:AudioClip[] = [];
        const _play = (clip:AudioClip)=>{
            if (!_playing){
                !this._isHide && this._playClip(clip,true,false);
                _playing = true;
                setTimeout((cur) => {
                    _playing = false;
                    const tmp = random ? App.Util.randomArray(clips):App.Util.getNextOrBack(clips,cur);
                    _play(tmp);
                }, this._audioSource.duration*1000,clip);
            }
        };
        paths = App.Util.confusionArray(paths);
        App.Asset.waitLoad(paths,(file:string,clip:AudioClip)=>{
            this._clips.set(file,clip);
            !this._audioSource.playing && !this._isHide && _play(clip);
            clips.indexOf(clip) === -1 && clips.push(clip);
        });
    };

    /**
     * 设置音乐（效）音量
     * @param volMusic 音乐音量
     * @param volEffect 音效音量
     */
    public setVolume(volMusic: number, volEffect: number): void {
        this._audioSource.volume = volMusic;
        this._audioVol = {music:volMusic,effect:volEffect};
        App.setLocalStorage(LocalKey.AUDIO,this._audioVol);
    };

    /**
     * 停止所有播放
     */
    public stopPlayAll(): void {
        this.setVolume(0,0);
    };

    /**
     * 获取音量，包括音乐和音效
     */
    public get volumes(): AudioVol {return this._audioVol;}

    private _playClip(clip:AudioClip,music:boolean,loop:boolean = true):void{
        const vol:number = music ? this._audioVol.music:this._audioVol.effect;
        if (vol < 0.1 || !App.isValid(clip)){
            return null;
        }
        if (!music){
            this._audioSource.playOneShot(clip,vol);
            return ;
        }

        this._audioSource.stop();
        this._audioSource.volume = vol;
        this._audioSource.clip = clip;
        this._audioSource.loop = loop;
        this._audioSource.play();
    }
};
